// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
#include <benchmark/benchmark.h>
#include <cstddef>
#include <random>
#include <vector>

using namespace std;

constexpr int tukey_ninther_adversary1[] = {0, 6, 12, 18, 22, 28, 34, 38, 44, 50, 54, 60, 66, 70, 76, 82, 86, 92, 98,
    102, 108, 114, 118, 124, 130, 134, 140, 146, 150, 156, 162, 166, 172, 178, 182, 188, 194, 198, 204, 210, 214, 220,
    226, 230, 236, 242, 246, 252, 258, 262, 268, 274, 278, 284, 290, 294, 300, 306, 310, 316, 322, 326, 332, 338, 342,
    348, 354, 358, 364, 370, 374, 380, 386, 390, 396, 402, 406, 412, 418, 422, 428, 434, 438, 444, 450, 454, 460, 466,
    470, 476, 482, 486, 492, 498, 502, 508, 514, 518, 524, 530, 534, 540, 546, 550, 556, 562, 566, 572, 578, 582, 588,
    594, 598, 604, 610, 614, 620, 626, 630, 636, 642, 646, 652, 658, 662, 668, 674, 678, 1, 7, 13, 684, 19, 23, 29, 690,
    35, 39, 45, 694, 51, 55, 61, 700, 67, 71, 77, 706, 83, 87, 93, 710, 99, 103, 109, 716, 115, 119, 125, 722, 131, 135,
    141, 726, 147, 151, 157, 732, 163, 167, 173, 738, 179, 183, 189, 742, 195, 199, 205, 748, 211, 215, 221, 754, 227,
    231, 237, 758, 243, 247, 253, 764, 259, 263, 269, 770, 275, 279, 285, 774, 291, 295, 301, 780, 307, 311, 317, 786,
    323, 327, 333, 790, 339, 343, 349, 796, 355, 359, 365, 802, 371, 375, 381, 806, 387, 391, 397, 812, 403, 407, 413,
    818, 419, 423, 429, 822, 435, 439, 445, 828, 451, 455, 461, 834, 467, 471, 477, 838, 483, 487, 493, 844, 499, 503,
    509, 850, 515, 519, 525, 854, 531, 535, 541, 860, 547, 551, 557, 866, 563, 567, 573, 870, 579, 583, 589, 876, 595,
    599, 605, 882, 611, 615, 621, 886, 627, 631, 637, 892, 643, 647, 653, 898, 659, 663, 669, 902, 675, 679, 685, 908,
    691, 695, 701, 914, 707, 711, 717, 918, 723, 727, 733, 924, 739, 743, 749, 930, 755, 759, 765, 934, 771, 775, 781,
    940, 787, 791, 797, 946, 803, 807, 813, 950, 819, 823, 829, 956, 835, 839, 845, 962, 851, 855, 861, 966, 867, 871,
    877, 972, 883, 887, 893, 978, 899, 903, 909, 982, 915, 919, 925, 988, 931, 935, 941, 990, 947, 951, 957, 992, 963,
    967, 973, 1024, 979, 983, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 2, 20, 8, 14, 24, 36, 30, 40, 52, 46,
    56, 68, 62, 72, 84, 78, 88, 100, 94, 104, 116, 110, 120, 132, 126, 136, 148, 142, 152, 164, 158, 168, 180, 174, 184,
    196, 190, 200, 212, 206, 216, 228, 222, 232, 244, 238, 248, 260, 254, 264, 276, 270, 280, 292, 286, 296, 308, 302,
    312, 324, 318, 328, 340, 334, 344, 356, 350, 360, 372, 366, 376, 388, 382, 392, 404, 398, 408, 420, 414, 424, 436,
    430, 440, 452, 446, 456, 468, 462, 472, 484, 478, 488, 500, 494, 504, 516, 510, 520, 532, 526, 536, 548, 542, 552,
    564, 558, 568, 580, 574, 584, 596, 590, 600, 612, 606, 616, 628, 622, 632, 644, 638, 648, 660, 654, 664, 676, 670,
    512, 3, 991, 9, 773, 768, 15, 680, 901, 21, 522, 25, 777, 527, 31, 692, 965, 37, 528, 41, 960, 778, 47, 686, 905,
    53, 538, 57, 936, 543, 63, 696, 1007, 69, 544, 73, 789, 784, 79, 708, 1014, 85, 554, 89, 793, 559, 95, 702, 969,
    101, 560, 105, 911, 794, 111, 712, 974, 117, 570, 121, 948, 575, 127, 724, 1015, 133, 576, 137, 805, 800, 143, 718,
    917, 149, 586, 153, 809, 591, 159, 728, 1008, 165, 592, 169, 970, 810, 175, 740, 921, 181, 602, 185, 942, 607, 191,
    734, 1009, 197, 608, 201, 821, 816, 207, 744, 975, 213, 618, 217, 825, 623, 223, 756, 1005, 229, 624, 233, 927, 826,
    239, 750, 984, 245, 634, 249, 952, 639, 255, 760, 1010, 261, 640, 265, 837, 832, 271, 772, 933, 277, 650, 281, 841,
    655, 287, 766, 981, 293, 656, 297, 976, 842, 303, 776, 937, 309, 666, 313, 964, 671, 319, 788, 1011, 325, 672, 329,
    853, 848, 335, 782, 1016, 341, 682, 345, 857, 687, 351, 792, 985, 357, 688, 361, 943, 858, 367, 804, 1003, 373, 698,
    377, 958, 703, 383, 798, 1017, 389, 704, 393, 869, 864, 399, 808, 949, 405, 714, 409, 873, 719, 415, 820, 1012, 421,
    720, 425, 986, 874, 431, 814, 953, 437, 730, 441, 968, 735, 447, 824, 1013, 453, 736, 457, 885, 880, 463, 836, 989,
    469, 746, 473, 889, 751, 479, 830, 1006, 485, 752, 489, 959, 890, 495, 840, 1004, 501, 762, 505, 980, 767, 511, 852,
    4, 517, 10, 521, 16, 896, 26, 846, 32, 533, 42, 537, 48, 783, 58, 856, 64, 549, 74, 553, 80, 906, 90, 868, 96, 565,
    106, 569, 112, 799, 122, 862, 128, 581, 138, 585, 144, 912, 154, 72, 160, 597, 170, 601, 176, 815, 186, 884, 192,
    613, 202, 617, 208, 922, 218, 878, 224, 629, 234, 633, 240, 831, 250, 888, 256, 645, 266, 649, 272, 928, 282, 900,
    288, 661, 298, 665, 304, 847, 314, 894, 320, 677, 330, 681, 336, 938, 346, 904, 352, 693, 362, 697, 368, 863, 378,
    916, 384, 709, 394, 713, 400, 944, 410, 910, 416, 725, 426, 729, 432, 879, 442, 920, 448, 741, 458, 745, 464, 954,
    474, 932, 480, 757, 490, 761, 496, 895, 506, 926, 5, 11, 17, 27, 33, 43, 49, 59, 65, 75, 81, 91, 97, 107, 113, 123,
    129, 139, 145, 155, 161, 71, 177, 187, 193, 203, 209, 219, 225, 235, 241, 251, 257, 267, 273, 283, 289, 299, 305,
    315, 321, 331, 337, 347, 353, 363, 369, 379, 385, 395, 401, 411, 417, 427, 433, 443, 449, 459, 465, 475, 481, 491,
    497, 507, 513, 523, 529, 539, 545, 555, 561, 571, 577, 587, 593, 603, 609, 619, 625, 635, 641, 651, 657, 667, 673,
    683, 689, 699, 705, 715, 721, 731, 737, 747, 753, 763, 769, 779, 785, 795, 801, 811, 817, 827, 833, 843, 849, 859,
    865, 875, 881, 891, 897, 907, 913, 923, 929, 939, 945, 955, 961, 971, 977, 987, 1018, 1019, 1020, 1021, 1022};

constexpr int tukey_ninther_adversary2[] = {1024, 31, 30, 29, 28, 36, 46, 51, 61, 67, 77, 82, 92, 98, 108, 118, 123,
    133, 139, 149, 154, 164, 170, 180, 190, 195, 205, 211, 221, 226, 236, 242, 252, 262, 267, 277, 283, 293, 298, 308,
    314, 324, 334, 339, 349, 355, 365, 370, 380, 386, 396, 406, 411, 421, 427, 437, 442, 452, 458, 468, 478, 483, 493,
    499, 509, 514, 524, 530, 540, 550, 555, 565, 571, 581, 586, 596, 602, 612, 622, 627, 637, 643, 653, 658, 668, 674,
    684, 694, 699, 709, 715, 725, 730, 740, 746, 756, 766, 771, 781, 787, 797, 802, 812, 818, 828, 838, 843, 853, 859,
    869, 874, 884, 890, 900, 910, 915, 925, 931, 941, 946, 956, 962, 972, 982, 987, 997, 1003, 1013, 1018, 343, 523,
    127, 529, 86, 539, 358, 549, 178, 554, 107, 564, 374, 570, 183, 580, 384, 585, 389, 595, 394, 601, 399, 611, 404,
    621, 409, 626, 18, 636, 419, 642, 425, 652, 318, 657, 435, 667, 440, 673, 169, 683, 450, 693, 224, 698, 256, 708,
    179, 714, 66, 724, 234, 729, 487, 739, 189, 745, 34, 755, 502, 765, 71, 770, 188, 780, 518, 786, 76, 796, 528, 801,
    533, 811, 538, 817, 543, 827, 548, 837, 553, 842, 163, 852, 563, 858, 569, 868, 286, 873, 579, 883, 584, 889, 70,
    899, 594, 909, 219, 914, 97, 924, 235, 930, 91, 940, 462, 945, 631, 955, 173, 961, 241, 971, 646, 981, 322, 986,
    272, 996, 662, 1002, 327, 1012, 672, 1017, 677, 1023, 682, 184, 687, 44, 692, 80, 697, 703, 390, 347, 707, 193, 713,
    718, 534, 276, 723, 26, 728, 734, 32, 200, 738, 744, 368, 749, 137, 754, 15, 759, 25, 764, 378, 769, 775, 575, 90,
    779, 148, 785, 790, 297, 215, 795, 225, 800, 806, 447, 56, 810, 816, 27, 821, 153, 826, 616, 831, 152, 836, 59, 841,
    847, 472, 632, 851, 116, 857, 862, 430, 214, 867, 647, 872, 878, 106, 251, 882, 888, 21, 893, 332, 898, 87, 903,
    132, 908, 678, 913, 919, 456, 168, 923, 230, 929, 934, 519, 466, 939, 19, 944, 950, 353, 471, 954, 960, 364, 965,
    719, 970, 271, 975, 544, 980, 369, 985, 991, 210, 491, 995, 282, 1001, 1006, 750, 250, 1011, 121, 1016, 1022, 385,
    292, 507, 65, 512, 255, 102, 776, 395, 45, 159, 287, 522, 260, 591, 791, 405, 117, 204, 307, 49, 265, 302, 807, 606,
    400, 22, 111, 16, 344, 822, 420, 313, 303, 415, 832, 275, 203, 559, 23, 416, 426, 323, 848, 281, 231, 209, 317, 574,
    436, 17, 863, 142, 333, 220, 488, 431, 441, 81, 879, 75, 590, 451, 663, 328, 446, 894, 296, 375, 600, 261, 904, 457,
    348, 605, 337, 610, 60, 688, 920, 467, 96, 615, 461, 620, 306, 354, 935, 477, 704, 625, 24, 312, 128, 143, 951, 476,
    635, 174, 131, 641, 240, 966, 492, 481, 138, 359, 976, 40, 363, 651, 735, 656, 498, 379, 992, 20, 497, 39, 560, 666,
    508, 112, 1007, 246, 158, 162, 760, 503, 513, 482, 291, 410, 245, 338, 199, 266, 147, 194, 101, 122, 55, 50, 14, 13,
    43, 48, 58, 64, 74, 79, 95, 105, 115, 120, 130, 136, 146, 151, 167, 177, 187, 192, 202, 208, 218, 223, 239, 249,
    259, 264, 274, 280, 290, 295, 311, 321, 331, 336, 346, 352, 362, 367, 383, 393, 403, 408, 418, 424, 434, 439, 455,
    465, 475, 480, 490, 496, 506, 511, 527, 537, 547, 552, 562, 568, 578, 583, 599, 609, 619, 624, 634, 640, 650, 655,
    671, 681, 691, 696, 706, 712, 722, 727, 743, 753, 763, 768, 778, 784, 794, 799, 815, 825, 835, 840, 850, 856, 866,
    871, 887, 897, 907, 912, 922, 928, 938, 943, 959, 969, 979, 984, 994, 1000, 1010, 1015, 1021, 1005, 990, 953, 974,
    964, 949, 933, 918, 881, 902, 892, 877, 861, 846, 809, 830, 820, 805, 789, 774, 737, 758, 748, 733, 717, 702, 665,
    686, 676, 661, 645, 630, 593, 614, 604, 589, 573, 558, 521, 542, 532, 517, 501, 486, 449, 470, 460, 445, 429, 414,
    377, 398, 388, 373, 357, 342, 305, 326, 316, 301, 285, 270, 233, 254, 244, 229, 213, 198, 161, 182, 172, 157, 141,
    126, 89, 110, 100, 85, 69, 54, 12, 38, 11, 10, 9, 8, 53, 84, 99, 125, 156, 171, 197, 228, 243, 269, 300, 315, 341,
    372, 387, 413, 444, 459, 485, 516, 531, 557, 588, 603, 629, 660, 675, 701, 732, 747, 773, 804, 819, 845, 876, 891,
    917, 948, 963, 989, 1020, 1014, 63, 253, 258, 263, 279, 273, 284, 289, 294, 310, 304, 320, 73, 325, 330, 335, 351,
    345, 356, 361, 366, 382, 376, 392, 88, 397, 402, 407, 423, 417, 428, 433, 438, 454, 448, 464, 109, 469, 474, 479,
    495, 489, 500, 505, 510, 526, 520, 536, 135, 541, 546, 551, 567, 561, 572, 577, 582, 598, 592, 608, 145, 613, 618,
    623, 639, 633, 644, 649, 654, 670, 664, 680, 160, 685, 690, 695, 711, 705, 716, 721, 726, 742, 736, 752, 181, 757,
    762, 767, 783, 777, 788, 793, 798, 814, 808, 824, 207, 829, 834, 839, 855, 849, 860, 865, 870, 886, 880, 896, 217,
    901, 906, 911, 927, 921, 932, 937, 942, 958, 952, 968, 232, 973, 978, 983, 999, 993, 1004, 1009, 248, 238, 222, 212,
    201, 191, 186, 37, 176, 166, 150, 140, 129, 119, 114, 3, 104, 94, 78, 68, 57, 47, 42, 6, 7, 4, 5, 2, -1, 33, 35, 41,
    52, 62, 72, 83, 93, 103, 113, 124, 134, 144, 155, 165, 175, 185, 196, 206, 216, 227, 237, 247, 257, 268, 278, 288,
    299, 309, 319, 329, 340, 350, 360, 371, 381, 391, 401, 412, 422, 432, 443, 453, 463, 473, 484, 494, 504, 515, 525,
    535, 545, 556, 566, 576, 587, 597, 607, 617, 628, 638, 648, 659, 669, 679, 689, 700, 710, 720, 731, 741, 751, 761,
    772, 782, 792, 803, 813, 823, 833, 844, 854, 864, 875, 885, 895, 905, 916, 926, 936, 947, 957, 967, 977, 988, 998,
    1008, 1019};

enum class alg_type { std_fn, rng };

template <alg_type Type, class Src>
void benchmark_common(benchmark::State& state, const Src& src) {
    vector<int> v;
    v.reserve(size(src));

    for (auto _ : state) {
        v.assign(begin(src), end(src));
        benchmark::DoNotOptimize(v);
        auto mid = v.begin() + (v.size() / 2);
        if constexpr (Type == alg_type::std_fn) {
            nth_element(v.begin(), mid, v.end());
        } else {
            ranges::nth_element(v.begin(), mid, v.end());
        }
        benchmark::DoNotOptimize(*mid);
    }
}

template <alg_type Type>
void bm_uniform(benchmark::State& state) {
    vector<int> src(static_cast<size_t>(state.range()));
    mt19937 gen(84710);
    uniform_int_distribution<int> dis(1, 580);
    ranges::generate(src, [&] { return dis(gen); });
    benchmark_common<Type>(state, src);
}

BENCHMARK(bm_uniform<alg_type::std_fn>)->Arg(1024)->Arg(2048)->Arg(4096)->Arg(8192);
BENCHMARK(bm_uniform<alg_type::rng>)->Arg(1024)->Arg(2048)->Arg(4096)->Arg(8192);

BENCHMARK_CAPTURE(benchmark_common<alg_type::std_fn>, adversary1, tukey_ninther_adversary1);
BENCHMARK_CAPTURE(benchmark_common<alg_type::rng>, adversary1, tukey_ninther_adversary1);
BENCHMARK_CAPTURE(benchmark_common<alg_type::std_fn>, adversary2, tukey_ninther_adversary2);
BENCHMARK_CAPTURE(benchmark_common<alg_type::rng>, adversary2, tukey_ninther_adversary2);

BENCHMARK_MAIN();
